
package com.be.beadmin.design.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.be.beadmin.common.entity.PageEntity;
import com.be.beadmin.common.exception.BeadminException;
import com.be.beadmin.common.utils.JpaQueryBuilder;
import com.be.beadmin.common.utils.JpaSortBuilder;
import com.be.beadmin.design.dto.input.*;
import com.be.beadmin.design.dto.output.BopEx;
import com.be.beadmin.design.dto.output.UnStandProductProcessInfoEx;
import com.be.beadmin.design.dto.output.UnStandProductWorkHourAndCycleEx;
import com.be.beadmin.design.entity.*;
import com.be.beadmin.design.mapper.UnStandProductProcessInfoMapper;
import com.be.beadmin.design.mapper.UnStandProductProcessInfoMapperEx;
import com.be.beadmin.design.repository.UnStandProductProcessInfoRepository;
import com.be.beadmin.design.service.BopTotalService;
import com.be.beadmin.design.service.StandProductProcessInfoService;
import com.be.beadmin.design.service.StandProductService;
import com.be.beadmin.design.service.UnStandProductProcessInfoService;
import com.be.beadmin.design.util.ExcelListener;
import com.be.beadmin.project.entity.BatchProduct;
import com.be.beadmin.project.repository.BatchProductRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* @description 服务实现
* @author cms
* @date 2023-09-13
**/
@Service
@RequiredArgsConstructor
public class UnStandProductProcessInfoServiceImpl implements UnStandProductProcessInfoService {

    @Autowired
    private  UnStandProductProcessInfoRepository unStandProductProcessInfoRepository;
    @Autowired
    private  UnStandProductProcessInfoMapper unStandProductProcessInfoMapper;
    @Autowired
    private  UnStandProductProcessInfoMapperEx unStandProductProcessInfoExMapper;

    @Autowired
    private StandProductProcessInfoService standProductProcessInfoService;

    @Autowired
    private StandProductService standProductService;

    @Autowired
    private BatchProductRepository batchProductRepository;

    @Autowired
    private BopTotalService bopTotalService;


    @Override
    public Page<BopPocessWorkHourAndCycle> getUnStandProductProcessInfoByPage(UnStandProductProcessInfoQueryCriteria unStandProductProcessInfoQueryCriteria) {

            PageEntity pageEntity = unStandProductProcessInfoQueryCriteria.getPageEntity();
            String unStandProductTypeId = unStandProductProcessInfoQueryCriteria.getProductId();
            Pageable pageable = PageRequest.of(
            pageEntity.getCurrent() -1,
            pageEntity.getPageSize());
            Page<UnStandProductProcessInfo> page = unStandProductProcessInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> list = new ArrayList<>();
                    Predicate pre1 =   JpaQueryBuilder.getPredicate(root, pageEntity.getFilters(), criteriaBuilder);
                    list.add(pre1);
                    Predicate pre2 = criteriaBuilder.equal(root.get(UnStandProductProcessInfo_.delete), 0); //过滤为0
                    list.add(pre2);
                    Predicate pre3 = criteriaBuilder.equal(root.get(UnStandProductProcessInfo_.unStandTypeId), unStandProductTypeId); //过滤为0
                    list.add(pre3);
                    Predicate[] p = new Predicate[list.size()];
                    List<Order> orders = new ArrayList<>();
                    if(pageEntity.getSorters() != null && pageEntity.getSorters().size() > 0) {
                        orders = JpaSortBuilder.getPredicate(root, pageEntity.getSorters(), criteriaBuilder);
                        criteriaQuery.orderBy(orders);
                    } else {
                        criteriaQuery.orderBy(criteriaBuilder.desc(root.get(UnStandProductProcessInfo_.createTime).as(Date.class)));
                    }
                    return  criteriaBuilder.and(list.toArray(p));
                    }
                    , pageable);
            Page<BopPocessWorkHourAndCycle> page1 = page.map(unStandProductProcessInfo -> {
                BopPocessWorkHourAndCycle target = new BopPocessWorkHourAndCycle();
                BeanUtils.copyProperties(unStandProductProcessInfo,target);
                return target;
            });
            return page1;
    }

    @Override
    public Page<Object> getPagedProductProcessInfo(UnStandProductProcessInfoQueryCriteria queryCriteria) {
        String productId = queryCriteria.getProductId();
        BatchProduct productInfo = batchProductRepository.findBatchProductByIdAndDelete(productId, 0);

        Page<?> res;
        if (productInfo.getIsStandard() == 1){
            // 标准柜先从据批次柜体id获取标准柜体编码，在得到实际的标准柜体id
            StandProduct standProduct = standProductService.getStandProductByCode(productInfo.getStandardProductCode());
            res = standProductProcessInfoService.getStandProductProcessInfoByStandTypeIdAndPage(new StandProductProcessInfoPageDto(standProduct.getId(),queryCriteria.getPageEntity()));
        }else{
            res = getUnStandProductProcessInfoByPage(queryCriteria);
        }
        return (Page<Object>) res;
    }


    @Override
    public void addUnStandProductProcessInfo(UnStandProductProcessInfoDto unStandProductProcessInfoDto) {

        UnStandProductProcessInfo result = unStandProductProcessInfoRepository.findUnStandProductProcessInfoByIdAndDelete(unStandProductProcessInfoDto.getId(), 0);
        if(ObjectUtil.isNotEmpty(result)) {
            throw new BeadminException("UnStandProductProcessInfo不存在,请重新查询");
        }
        UnStandProductProcessInfo unStandProductProcessInfo = unStandProductProcessInfoMapper.toEntity(unStandProductProcessInfoDto);
        unStandProductProcessInfoRepository.save(unStandProductProcessInfo);

    }

    @Override
    public void updateUnStandProductProcessInfo(UnStandProductProcessInfoDto unStandProductProcessInfoDto) {
            UnStandProductProcessInfo unStandProductProcessInfo = unStandProductProcessInfoRepository.findUnStandProductProcessInfoById(unStandProductProcessInfoDto.getId());
            unStandProductProcessInfo = unStandProductProcessInfoMapper.toEntity(unStandProductProcessInfoDto);
            unStandProductProcessInfoRepository.save(unStandProductProcessInfo);
    }


    @Override
    public void delUnStandProductProcessInfo(String id) {
        UnStandProductProcessInfo unStandProductProcessInfo = unStandProductProcessInfoRepository.findUnStandProductProcessInfoById(id);
        unStandProductProcessInfo.setDelete(1);
        unStandProductProcessInfoRepository.save(unStandProductProcessInfo);
    }

    @Override
    public void delUnStandProductProcessInfos (List<String> ids) { }



    @Transactional
    @Override
    public void addUnStandProductBopAndProcessDto(UnStandProductBopAndProcessDto unStandProductBopAndProcessDto) {


        for (BopPocessWorkHourAndCycle item : unStandProductBopAndProcessDto.getBopPocessWorkHourAndCycleList()) {
            if (item.getIsProductionProcess() == 0){
                continue;
            }
            if (item.getStandWorkHour() <= 0 || item.getStandCycle() < 0){
                throw new BeadminException("工时不能为0或负数，周期不能为负数");
            }
        }

        unStandProductProcessInfoRepository.deleteAllByUnStandTypeId(unStandProductBopAndProcessDto.getUnStandTypeId());

        // 设置非标柜体工序及工时
        List<UnStandProductProcessInfoDto> newlist = new ArrayList<>();
        for(BopPocessWorkHourAndCycle item : unStandProductBopAndProcessDto.getBopPocessWorkHourAndCycleList()){
            UnStandProductProcessInfoDto unStandProductProcessInfoDto = new UnStandProductProcessInfoDto();
            unStandProductProcessInfoDto.setIsProductionProcess(item.getIsProductionProcess());
            unStandProductProcessInfoDto.setShowSelfInspection(item.getShowSelfInspection());
            unStandProductProcessInfoDto.setProcessCode(item.getProcessCode());
            unStandProductProcessInfoDto.setProcessId(item.getProcessId());
            unStandProductProcessInfoDto.setProcessName(item.getProcessName());
            unStandProductProcessInfoDto.setSequence(item.getSequence());
            unStandProductProcessInfoDto.setStandWorkHour(item.getStandWorkHour());
            unStandProductProcessInfoDto.setStandCycle(item.getStandCycle());
            newlist.add(unStandProductProcessInfoDto);
        }

        // 设置非标准柜体信息
        for (UnStandProductProcessInfoDto item : newlist){
            item.setBopCode(unStandProductBopAndProcessDto.getBopCode());
            item.setUnStandTypeId(unStandProductBopAndProcessDto.getUnStandTypeId());
            item.setUnStandTypeCode(unStandProductBopAndProcessDto.getUnStandTypeCode());
            item.setUnStandTypeName(unStandProductBopAndProcessDto.getUnStandTypeName());
            item.setUnStandTypeDesc(unStandProductBopAndProcessDto.getUnStandTypeDesc());
        }

        List<UnStandProductProcessInfo> unStandProductProcessInfoList = unStandProductProcessInfoMapper.toEntity(newlist);
        unStandProductProcessInfoRepository.saveAll(unStandProductProcessInfoList);

        BatchProduct batchProduct = batchProductRepository.findBatchProductById(unStandProductBopAndProcessDto.getUnStandTypeId());
        batchProduct.setBopCode(unStandProductBopAndProcessDto.getBopCode());
        batchProduct.setIsDesignBop(1);
        batchProduct.setIsStdWorkHourUploaded(1);
        batchProductRepository.save(batchProduct);
    }

    @Override
    public UnStandProductProcessInfoEx getUnStandProductProcessInfo(String unStandTypeId) {

        List<UnStandProductProcessInfo> list = unStandProductProcessInfoRepository.findUnStandProductProcessInfoByUnStandTypeIdAndDeleteOrderBySequence(unStandTypeId,0);

        if (list.isEmpty()){
            throw new BeadminException("该柜体不是非标柜体");
        }

        List<BopPocessWorkHourAndCycle> bopPocessWorkHourAndCycleList = new ArrayList<>();

        for (UnStandProductProcessInfo item : list){
            BopPocessWorkHourAndCycle bopPocessWorkHourAndCycle = new BopPocessWorkHourAndCycle();
            bopPocessWorkHourAndCycle.setProcessId(item.getProcessId());
            bopPocessWorkHourAndCycle.setStandWorkHour(item.getStandWorkHour());
            bopPocessWorkHourAndCycle.setProcessName(item.getProcessName());
            bopPocessWorkHourAndCycle.setStandCycle(item.getStandCycle());
            bopPocessWorkHourAndCycle.setSequence(item.getSequence());
            bopPocessWorkHourAndCycle.setIsProductionProcess(item.getIsProductionProcess());
            bopPocessWorkHourAndCycle.setShowSelfInspection(item.getShowSelfInspection());
            bopPocessWorkHourAndCycle.setProcessCode(item.getProcessCode());
            bopPocessWorkHourAndCycleList.add(bopPocessWorkHourAndCycle);
        }

        UnStandProductProcessInfoEx unStandProductProcessInfoEx = new UnStandProductProcessInfoEx();

        unStandProductProcessInfoEx.setBopPocessWorkHourAndCycle(bopPocessWorkHourAndCycleList);
        unStandProductProcessInfoEx.setBopCode(list.get(0).getBopCode());

        return unStandProductProcessInfoEx ;
    }

    @Override
    public void setBop(String unStandTypeId, String bopCode) {

        BopTotal bopTotal = bopTotalService.getBopTotalByBopCode(bopCode);
        BopEx bop = bopTotalService.getBopTotalById(bopTotal.getId());
        BatchProduct batchProduct = batchProductRepository.findBatchProductByIdAndDelete(unStandTypeId,0);

        if(!bopCode.equals(batchProduct.getBopCode())) {
            unStandProductProcessInfoRepository.deleteAllByUnStandTypeId(unStandTypeId);
            batchProduct.setBopIsChange(1);
            batchProduct.setIsStdWorkHourUploaded(0);       // 更改工艺路径，工时需要重新上传
        }else {
            // 工艺路径未更改
            return;
        }

        List<UnStandProductProcessInfoDto> list = new ArrayList<>();
        for (BopInfo item: bop.getBopInfoList()){
            UnStandProductProcessInfoDto unStandProductProcessInfoDto = new UnStandProductProcessInfoDto();
            unStandProductProcessInfoDto.setBopCode(item.getBopCode());

            unStandProductProcessInfoDto.setProcessId(item.getProcessId());
            unStandProductProcessInfoDto.setShowSelfInspection(item.getShowSelfInspection());
            unStandProductProcessInfoDto.setIsProductionProcess(item.getIsProductionProcess());
            unStandProductProcessInfoDto.setProcessCode(item.getProcessCode());
            unStandProductProcessInfoDto.setProcessName(item.getProcessName());
            unStandProductProcessInfoDto.setSequence(item.getSequence());
            unStandProductProcessInfoDto.setStandCycle(0);
            unStandProductProcessInfoDto.setStandWorkHour(0F);

            unStandProductProcessInfoDto.setUnStandTypeId(unStandTypeId);
            unStandProductProcessInfoDto.setUnStandTypeName(batchProduct.getProductType());
            unStandProductProcessInfoDto.setUnStandTypeCode(batchProduct.getProductCode());

            list.add(unStandProductProcessInfoDto);
        }

        List<UnStandProductProcessInfo> unStandProductProcessInfoList = unStandProductProcessInfoMapper.toEntity(list);
        unStandProductProcessInfoRepository.saveAll(unStandProductProcessInfoList);

        // 修改batchProduct中信息
        batchProduct.setBopCode(bopCode);
        batchProduct.setIsDesignBop(1);
        batchProductRepository.save(batchProduct);

    }

    @Override
    public void setInitialBop(String unStandTypeId, String unStandTypeCode, String unStandTypeName,String bopCode) {
        unStandProductProcessInfoRepository.deleteAllByUnStandTypeId(unStandTypeId);

        BopTotal bopTotal = bopTotalService.getBopTotalByBopCode(bopCode);

        BopEx bop = bopTotalService.getBopTotalById(bopTotal.getId());

        List<UnStandProductProcessInfoDto> list = new ArrayList<>();
        for (BopInfo item: bop.getBopInfoList()){
            UnStandProductProcessInfoDto unStandProductProcessInfoDto = new UnStandProductProcessInfoDto();
            unStandProductProcessInfoDto.setBopCode(item.getBopCode());

            unStandProductProcessInfoDto.setProcessId(item.getProcessId());
            unStandProductProcessInfoDto.setShowSelfInspection(item.getShowSelfInspection());
            unStandProductProcessInfoDto.setIsProductionProcess(item.getIsProductionProcess());
            unStandProductProcessInfoDto.setProcessCode(item.getProcessCode());
            unStandProductProcessInfoDto.setProcessName(item.getProcessName());
            unStandProductProcessInfoDto.setSequence(item.getSequence());
            unStandProductProcessInfoDto.setStandCycle(0);
            unStandProductProcessInfoDto.setStandWorkHour(0F);

            unStandProductProcessInfoDto.setUnStandTypeId(unStandTypeId);
            unStandProductProcessInfoDto.setUnStandTypeName(unStandTypeName);
            unStandProductProcessInfoDto.setUnStandTypeCode(unStandTypeCode);

            list.add(unStandProductProcessInfoDto);
        }

        List<UnStandProductProcessInfo> unStandProductProcessInfoList = unStandProductProcessInfoMapper.toEntity(list);
        unStandProductProcessInfoRepository.saveAll(unStandProductProcessInfoList);
    }

    @Override
    public List<UnStandProductWorkHourAndCycleEx> getUnstandProductWorkHourAndCycleByProjectInfo(String projectId,String projectName, String projectCode) {
        List<BatchProduct> batchProducts = batchProductRepository.findBatchProductByInfoIdAndReviewStateAndDelete(projectId,0,0);     // 排除项目下的标准柜体

        List<UnStandProductWorkHourAndCycleEx> unStandProductWorkHourAndCycleExes = new ArrayList<>();

        for (BatchProduct item :batchProducts){
            List<UnStandProductProcessInfo> processInfo = unStandProductProcessInfoRepository.findUnStandProductProcessInfoByUnStandTypeIdAndDeleteOrderBySequence(item.getId(), 0);

            for (UnStandProductProcessInfo item2 : processInfo){
                UnStandProductWorkHourAndCycleEx res = new UnStandProductWorkHourAndCycleEx();
                res.setProjectCode(projectCode);
                res.setProjectName(projectName);

                res.setUnStandTypeName(item2.getUnStandTypeName());
                res.setUnStandTypeCode(item2.getUnStandTypeCode());
                res.setUnStandTypeDesc(item2.getUnStandTypeDesc());

                res.setProcessCode(item2.getProcessCode());
                res.setProcessName(item2.getProcessName());
                res.setIsProductionProcess(item2.getIsProductionProcess());
                res.setStandCycle(item2.getStandCycle());
                res.setStandWorkHour(item2.getStandWorkHour());

                unStandProductWorkHourAndCycleExes.add(res);
            }
        }

        return unStandProductWorkHourAndCycleExes;
    }

    @Override
    public List<UnStandProductWorkHourAndCycleEx> getUnstandProductWorkHourAndCycleByProductIds(List<String> productIds) {

        List<BatchProduct> batchProducts = batchProductRepository.findBatchProductsByIdInAndDelete(productIds, 0);
        List<UnStandProductWorkHourAndCycleEx> unStandProductWorkHourAndCycleExes = new ArrayList<>();

        for (BatchProduct item :batchProducts){
            List<UnStandProductProcessInfo> processInfo = unStandProductProcessInfoRepository.findUnStandProductProcessInfoByUnStandTypeIdAndDeleteOrderBySequence(item.getId(), 0);

            for (UnStandProductProcessInfo item2 : processInfo){
                UnStandProductWorkHourAndCycleEx res = new UnStandProductWorkHourAndCycleEx();
                res.setProjectCode(item.getProjectCode());
                res.setProjectName(item.getProjectName());

                res.setUnStandTypeName(item2.getUnStandTypeName());
                res.setUnStandTypeCode(item2.getUnStandTypeCode());
                res.setUnStandTypeDesc(item2.getUnStandTypeDesc());

                res.setProcessCode(item2.getProcessCode());
                res.setProcessName(item2.getProcessName());
                res.setIsProductionProcess(item2.getIsProductionProcess());
                res.setStandCycle(item2.getStandCycle());
                res.setStandWorkHour(item2.getStandWorkHour());

                unStandProductWorkHourAndCycleExes.add(res);
            }
        }

        return unStandProductWorkHourAndCycleExes;
    }


    @Transactional
    @Override
    public void uploadWorkhourAndCycle(MultipartFile file) {

        ExcelListener<UnStandProductWorkHourAndCycleEx> excelListener = new ExcelListener<>();
        try{
            ExcelReader excelReader = EasyExcelFactory.read(file.getInputStream(),UnStandProductWorkHourAndCycleEx.class ,excelListener).headRowNumber(1).build();
            excelReader.readAll();
            excelReader.finish();
        }catch (ExcelDataConvertException e){
            throw new BeadminException("表中数据类型有误");
        }catch (Exception e) {
            throw new BeadminException("解析失败");
        }

        List<UnStandProductWorkHourAndCycleEx> dataList = excelListener.getDatas();
        for (UnStandProductWorkHourAndCycleEx item : dataList){
            if (item.getProjectCode() == null){
                throw new BeadminException("请使用正确的模板");
            }
            if (item.getStandWorkHour() <= 0 || item.getStandCycle() < 0){
                throw new BeadminException("工时不能为0或负数，周期不能为负数");
            }
            UnStandProductProcessInfo res = unStandProductProcessInfoRepository.findUnStandProductProcessInfoByUnStandTypeCodeAndAndProcessCode(item.getUnStandTypeCode(), item.getProcessCode());
            res.setStandWorkHour(item.getStandWorkHour());
            res.setStandCycle(item.getStandCycle());
            unStandProductProcessInfoRepository.save(res);

            // 已设置工时
            BatchProduct batchProduct = batchProductRepository.findBatchProductById(res.getUnStandTypeId());
            batchProduct.setIsStdWorkHourUploaded(1);
            batchProductRepository.save(batchProduct);
        }

    }

    public UnStandBopInfo getBopInfo(String unStandTypeId){
        BatchProduct batchProduct = batchProductRepository.findBatchProductByIdAndDelete(unStandTypeId,0);

        UnStandBopInfo unStandBopInfo = new UnStandBopInfo();
        unStandBopInfo.setBopCode(batchProduct.getBopCode());
        unStandBopInfo.setBopIsChange(batchProduct.getBopIsChange());

        return unStandBopInfo;
    }


}